package com.ccom.user.controller;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ccom.api.constant.UserCommonConstant;
import com.ccom.api.domain.User;
import com.ccom.api.dto.SmsLoginModel;
import com.ccom.api.dto.SysLoginModel;
import com.ccom.api.vo.LoginVo;
import com.ccom.api.vo.UserVo;
import com.ccom.core.common.constant.CacheConstant;
import com.ccom.core.common.constant.CommonConstant;
import com.ccom.core.common.constant.SecurityConstants;
import com.ccom.core.common.constant.ServiceNameConstants;
import com.ccom.core.common.enums.ExceptionEnums;
import com.ccom.core.common.exception.RemindException;
import com.ccom.core.common.model.Result;
import com.ccom.core.common.util.*;
import com.ccom.core.common.util.encryption.EncryptedString;
import com.ccom.redis.util.RedisUtil;
import com.ccom.sms.properties.DySmsEnum;
import com.ccom.sms.util.DySmsHelper;
import com.ccom.user.service.UserService;
import com.ccom.user.sync.UserSync;
import com.ccom.user.util.RandImageUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * 用户登录
 */
@Slf4j
@Api(tags = "用户登录")
@RestController
@RequestMapping(ServiceNameConstants.USER_SERVICE_URL_PREFIX + "/auth")
public class LoginController {

    @Autowired
    private UserService userService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserSync userSync;

    @Autowired
    private DySmsHelper dySmsHelper;

    private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";

    @ApiOperation("账号密码登录接口")
    @PostMapping(value = "/login")
    public Result<LoginVo> login(@RequestBody SysLoginModel sysLoginModel) {

        String username = sysLoginModel.getUserName();
        String password = sysLoginModel.getPassword();

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName, username);
        User user = userService.getOne(queryWrapper);

        userService.checkUserIsEffective(user);
        if (StringUtils.isEmpty(user.getPassword())) {
            throw new RemindException(ExceptionEnums.USER_NO_PASSWORD);
        }

        //2. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, user.getSalt());
        String syspassword = user.getPassword();
        if (!syspassword.equals(userpassword)) {
            throw new RemindException(ExceptionEnums.USER_PASSWORD_NAME_ERROR);
        }

        //3.设置token缓存有效时间
        String token = JwtUtil.sign(String.valueOf(user.getId()), username, syspassword);
        redisUtil.set(CacheConstant.PREFIX_USER_TOKEN + user.getId(), token);
        redisUtil.expire(CacheConstant.PREFIX_USER_TOKEN + user.getId(), JwtUtil.EXPIRE_TIME * 2 / 1000);

        UserVo userVo = BeanUtils.copy(user, UserVo.class);

        userSync.saveLoginLog(user, UserCommonConstant.LOGIN_TYPE, UserCommonConstant.SUCCESS_STATUS);
        return Result.date(new LoginVo(token, userVo), "登录成功");
    }

    /**
     * 退出登录
     *
     * @param request
     * @param response
     * @return
     */
    @ApiOperation("退出登录")
    @PostMapping(value = "/logout")
    public Result<Object> logout(HttpServletRequest request, HttpServletResponse response) {
        //用户退出逻辑
        String token = request.getHeader(SecurityConstants.X_ACCESS_TOKEN);
        if (StringUtils.isEmpty(token)) {
            return Result.error("退出登录失败！");
        }
        String username = JwtUtil.getUsername(token);
        User user = userService.getUserByName(username);
        if (user != null) {
            userSync.saveLoginLog(user, UserCommonConstant.LOGOUT_TYPE, UserCommonConstant.SUCCESS_STATUS);
            redisUtil.del(CacheConstant.PREFIX_USER_TOKEN + user.getId());
            return Result.success("退出登录成功！");
        } else {
            return Result.error("Token无效!");
        }
    }

    /**
     * 短信验证码发送接口(注册、登录、忘记密码)
     *
     * @param smsLoginModel
     * @return
     */
    @ApiOperation("短信验证码发送接口")
    @PostMapping(value = "/smsSend")
    public Result smsSend(@RequestBody SmsLoginModel smsLoginModel) {
        String mobile = smsLoginModel.getPhoneNumber();
        int smsmode = smsLoginModel.getType();

        if (StringUtils.isEmpty(mobile)) {
            throw new RemindException(ExceptionEnums.USER_PHONE_NOT_NULL);
        }
        Object object = redisUtil.get(CacheConstant.PREFIX_PHONE_CAPTCHA + mobile);
        if (object != null) {
            throw new RemindException(ExceptionEnums.USER_CAPTCHA_IN_USE);
        }

        //随机数验证码
        String captcha = RandomUtil.randomNumbers(6);
        JSONObject obj = new JSONObject();
        obj.put("code", captcha);
        try {
            User user = userService.getUserByPhone(mobile);
            boolean b = false;
            if (CommonConstant.SMS_TPL_TYPE_1.equals(smsmode)) {
                //注册模版
                if (user != null) {
//					baseCommonService.addLog("手机号已经注册，请直接登录！", CommonConstant.LOG_TYPE_1, null);
                    throw new RemindException(ExceptionEnums.USER_PHONE_IS_REGISTER);
                }
                b = dySmsHelper.sendSms(mobile, obj, DySmsEnum.REGISTER_SMS_TEMPLATE);
            } else {
                //校验用户有效性
                userService.checkUserIsEffective(user);

                if (CommonConstant.SMS_TPL_TYPE_0.equals(smsmode)) {
                    //登录模版
                    b = dySmsHelper.sendSms(mobile, obj, DySmsEnum.LOGIN_SMS_TEMPLATE);
                } else if (CommonConstant.SMS_TPL_TYPE_2.equals(smsmode)) {
                    //忘记密码模版
                    b = dySmsHelper.sendSms(mobile, obj, DySmsEnum.FORGET_PASSWORD_SMS_TEMPLATE);
                }
            }

            if (b == false) {
                throw new RemindException(ExceptionEnums.USER_CAPTCHA_SEND_ERROR);
            }
            redisUtil.set(CacheConstant.PREFIX_PHONE_CAPTCHA + mobile, captcha, 600);
        } catch (ClientException e) {
            e.printStackTrace();
            return Result.error("验证码发送失败");
        }
        return Result.success();
    }


    /**
     * 手机号登录接口
     *
     * @param smsLoginModel
     * @return
     */
    @ApiOperation("手机号登录接口")
    @PostMapping("/phoneLogin")
    public Result phoneLogin(@RequestBody SmsLoginModel smsLoginModel) {
        String phone = smsLoginModel.getPhoneNumber();
        String smscode = smsLoginModel.getCaptcha();

        //校验用户有效性
        User user = userService.getUserByPhone(phone);
        userService.checkUserIsEffective(user);

        Object code = redisUtil.get(CacheConstant.PREFIX_PHONE_CAPTCHA + phone);
        if (!smscode.equals(code)) {
            return Result.remind("验证码错误");
        }

        String syspassword = user.getPassword();
        String username = user.getUserName();
        Long id = user.getId();
        String token = JwtUtil.sign(String.valueOf(id), username, syspassword);

        // 设置token缓存有效时间
        redisUtil.set(CacheConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CacheConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);

        UserVo userVo = BeanUtils.copy(user, UserVo.class);

        userSync.saveLoginLog(user, UserCommonConstant.LOGIN_TYPE, UserCommonConstant.SUCCESS_STATUS);
        return Result.date(new LoginVo(token, userVo), "登录成功");
    }

    /**
     * 获取加密字符串
     *
     * @return
     */
    @ApiOperation("获取加密字符串")
    @GetMapping(value = "/getEncryptedString")
    public Result<Map<String, String>> getEncryptedString() {
        Result<Map<String, String>> result = new Result<Map<String, String>>();
        Map<String, String> map = new HashMap<String, String>();
        map.put("key", EncryptedString.key);
        map.put("iv", EncryptedString.iv);
        result.setResult(map);
        return result;
    }

    /**
     * 后台生成图形验证码:有效
     *
     * @param response
     * @param key
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/randomImage/{key}")
    public Result<String> randomImage(HttpServletResponse response, @PathVariable String key) {
        try {
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            String lowerCaseCode = code.toLowerCase();
            String realKey = MD5Util.MD5Encode(lowerCaseCode + key, "utf-8");
            redisUtil.set(realKey, lowerCaseCode, 60);
            String base64 = RandImageUtil.generate(code);
            return Result.date(base64);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("获取验证码出错" + e.getMessage());
        }
    }

    /**
     * 图形验证码
     *
     * @param sysLoginModel
     * @return
     */
    @ApiOperation("图形验证码")
    @PostMapping(value = "/checkCaptcha")
    public Result<?> checkCaptcha(@RequestBody SysLoginModel sysLoginModel) {
        String captcha = sysLoginModel.getCaptcha();
        String checkKey = sysLoginModel.getCheckKey();
        if (captcha == null) {
            return Result.error("验证码无效");
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + checkKey, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        if (checkCode == null || !checkCode.equals(lowerCaseCaptcha)) {
            return Result.error("验证码错误");
        }
        return Result.success();
    }

}